package edu.buaa.energy;

import cn.leancloud.LCObject;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SimplePropertyPreFilter;
import com.aliyun.openservices.aliyun.log.producer.Producer;
import com.aliyun.openservices.aliyun.log.producer.errors.ProducerException;
import edu.buaa.common.BenchmarkReader;
import edu.buaa.common.TxResultProcessor;
import edu.buaa.common.client.DBProxy;
import edu.buaa.common.client.TGraphExecutorClient;
import edu.buaa.common.client.Neo4jExecutorClient;
import edu.buaa.common.transaction.AbstractTransaction;
import edu.buaa.energy.client.MariaDBClient;
import edu.buaa.energy.client.PostgreSQLClient;
import edu.buaa.utils.Helper;
import edu.buaa.utils.TimeTicker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Calendar;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class BenchmarkRunner {
    private static final Logger log = LoggerFactory.getLogger(BenchmarkRunner.class);

    public static void main(String[] args) throws IOException, InterruptedException, ProducerException {
        Producer logger = Helper.getLogger();
        DBProxy client = null;
        TxResultProcessor post = null;
        BenchmarkReader reader = null;
        TimeTicker ticker = new TimeTicker(30, 2);
        try {
            String benchmarkFileName = Helper.mustEnv("BENCHMARK_FULL_PATH");
            String dbType = Helper.mustEnv("DB");
            int maxConnCnt = Integer.parseInt(Helper.mustEnv("MAX_CONNECTION_CNT"));
            String dbHost = Helper.mustEnv("DB_HOST");
            boolean needResult = Boolean.parseBoolean(Helper.mustEnv("NEED_RESULT"));
            String resultFile = needResult ? Helper.mustEnv("BENCHMARK_RESULT_PATH") : "";

            client = initClient(dbType, dbHost, maxConnCnt);
            String serverVersion = client.testServerClientCompatibility();
            File benchmarkFile = new File(benchmarkFileName);
            String testName = Helper.getTestName(benchmarkFile.getName(), dbType);
            post = new TxResultProcessor(testName, Helper.codeGitVersion());
            post.setLogger(logger);
            if(needResult) post.setResult(new File(resultFile));
            post.setVerifyResult(false);
            reader = new BenchmarkReader(benchmarkFile, !needResult);
            SimplePropertyPreFilter pf = new SimplePropertyPreFilter();
            pf.getExcludes().addAll(Arrays.asList("txType", "metrics", "result",
                    "nodes", "rels",
                    "crosses", "roads", "data" // for traffic dataset
            ));
            while (reader.hasNext()) {
                AbstractTransaction tx = reader.next();
                if(needResult){
                    post.processSync(client.execute(tx), tx);
                }else{
                    post.process(client.execute(tx), tx);
                }
                if(ticker.shouldTick()) log.debug(JSON.toJSONString(tx, pf));
            }
            saveTest2db(dbType, maxConnCnt, testName);
//            System.exit(0);
//        } catch (ConnectException e){
//            System.exit(3);
        }catch (Exception e) {
            log.error("ERROR sending request", e);
            Helper.trace().notifyError(e);
            throw new RuntimeException(e);
//            System.exit(-1);
        }finally {
            if(reader!=null) reader.close();
            if(client!=null) client.close();
            if(post!=null) post.close();
            logger.close();
        }
    }

    private static void saveTest2db(String dbType, int maxConnCnt, String testName) {
        Pattern pattern = Pattern.compile("(energy\\.\\d_\\d+-\\d+)");
        Matcher matcher = pattern.matcher(testName);
        LCObject testObject = new LCObject("TGraphTest");
        testObject.put("DB", dbType);
        testObject.put("Dataset", "energy");
        testObject.put("MSize", matcher.find()?matcher.group(0):"");
        testObject.put("maxCon", maxConnCnt);
        testObject.put("TestName", testName);
        testObject.save();
    }

    private static DBProxy initClient(String dbType, String dbHost, int maxConnCnt) throws Exception {
        switch (dbType.toLowerCase()) {
            case "mariadb":
                return new MariaDBClient(dbHost, maxConnCnt);
            case "postgresql":
                return new PostgreSQLClient(dbHost, maxConnCnt);
            case "tgraph_kernel":
            case "tgraph_kernel_e":
                return new TGraphExecutorClient(dbHost, maxConnCnt);
            case "neo4j1":
                return new Neo4jExecutorClient(dbHost, 9833, maxConnCnt);
            case "neo4j2":
                return new Neo4jExecutorClient(dbHost, 9866, maxConnCnt);
            default:
                throw new UnsupportedOperationException();
        }
    }

}
